﻿using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using ReadyApps.Common;
using ReadyApps.Data.Wiki;
using ReadyApps.Wiki.Templates;

namespace ReadyApps.Wiki.Views
{
    class EditPermissionsView : ViewBase
    {
        #region Inner Classes

        class PrivilegeColumn
        {
            #region Properties

            public string HeaderText { get; private set; }
            public string CheckboxPrefix { get; private set; }
            public string NewCheckboxID { get; private set; }
            public Func<RolePrivileges, bool> GetValue { get; private set; }
            public Action<RolePrivileges, bool> SetValue { get; private set; }

            #endregion

            #region Constructor

            public PrivilegeColumn(string headerText, string checkboxPrefix, string newCheckboxID,
                Func<RolePrivileges, bool> getValue, Action<RolePrivileges, bool> setValue)
            {
                HeaderText = headerText;
                CheckboxPrefix = checkboxPrefix;
                NewCheckboxID = newCheckboxID;
                GetValue = getValue;
                SetValue = setValue;
            }

            #endregion
        }

        #endregion

        #region Variables and Constants

        private const string NEW_ROLE_NAME_TEXTBOX_ID = "txtNewRole";

        private readonly static PrivilegeColumn[] columns = new[] {
            new PrivilegeColumn("View Page", "chkViewPage_", "chkNewViewPage",
                rp => rp.Privileges.ViewPage, (rp, v) => rp.Privileges.ViewPage = v),
            new PrivilegeColumn("Edit Page", "chkEditPage_", "chkNewEditPage",
                rp => rp.Privileges.EditPage, (rp, v) => rp.Privileges.EditPage = v),
            new PrivilegeColumn("Create Page", "chkCreatePage_", "chkNewCreatePage",
                rp => rp.Privileges.CreatePage, (rp, v) => rp.Privileges.CreatePage = v),
            new PrivilegeColumn("Create Folder", "chkCreateFolder_", "chkNewCreateFolder",
                rp => rp.Privileges.CreateFolder, (rp, v) => rp.Privileges.CreateFolder = v),
            new PrivilegeColumn("Edit Permissions", "chkEditPermissions_", "chkNewEditPermissions",
                rp => rp.Privileges.EditPermissions, (rp, v) => rp.Privileges.EditPermissions = v),
            new PrivilegeColumn("Manage Revisions", "chkManageRevisions_", "chkNewManageRevisions",
                rp => rp.Privileges.ManageRevisions, (rp, v) => rp.Privileges.ManageRevisions = v),
            new PrivilegeColumn("Manage Publishing", "chkManagePublishing_", "chkNewManagePublishing",
                rp => rp.Privileges.ManagePublishing, (rp, v) => rp.Privileges.ManagePublishing = v)
        };

        private EditPermissions editPermissionsData;
        private ControlCollection controlsRef;

        #endregion

        #region Events

        private event EventHandler cancelButtonClick;
        public event EventHandler CancelButtonClick
        {
            add { cancelButtonClick += value; }
            remove { cancelButtonClick -= value; }
        }

        private event EventHandler saveButtonClick;
        public event EventHandler SaveButtonClick
        {
            add { saveButtonClick += value; }
            remove { saveButtonClick -= value; }
        }

        private event EventHandler removeSpecificButtonClick;
        public event EventHandler RemoveSpecificButtonClick
        {
            add { removeSpecificButtonClick += value; }
            remove { removeSpecificButtonClick -= value; }
        }

        #endregion

        #region Constructor

        public EditPermissionsView(WikiControlSettings wikiControlSettings, EditPermissions wikiPermissionsData)
            : base(wikiControlSettings)
        {
            editPermissionsData = wikiPermissionsData;
        }

        #endregion

        #region Public Methods

        public override void BuildControlTree(ControlCollection controls, bool raiseEvents)
        {
            controls.Clear();
            controlsRef = controls;
            Control container = new Control();

            container.Controls.Add(GeneratePermissionsHierarchy(editPermissionsData.Hierarchy));

            // Display clone permission set message
            if (editPermissionsData.PermissionsAreInherited)
            {
                container.Controls.Add(new Literal()
                {
                    Text = @"<p>
These permissions are inherited from a folder and may be associated with
other pages. By checking the checkbox below, the original permissions will
be modified. If the checkbox is not checked, the modified permissions will
only apply to this page.
</p>
<p>"
                });
                CheckBox modifyOriginalPermissions = new CheckBox();
                modifyOriginalPermissions.Checked = editPermissionsData.ModifyOriginalPermissions;
                modifyOriginalPermissions.Text = "Modify the original permissions";
                modifyOriginalPermissions.CheckedChanged += new EventHandler(modifyOriginalPermissions_CheckedChanged);
                container.Controls.Add(modifyOriginalPermissions);
                container.Controls.Add(new Literal() { Text = "</p>" });
            }
            else
            {
                container.Controls.Add(new Literal()
                {
                    Text = @"<p>
These permissions are specific to this page. To remove these permissions
and use the permissions from a folder, click the button below.
</p>
<p>"
                });
                Button removeSpecificPermissions = new Button();
                removeSpecificPermissions.Text = "Remove Page-Specific Permissions";
                removeSpecificPermissions.Click += removeSpecificButtonClick;
                container.Controls.Add(removeSpecificPermissions);
                container.Controls.Add(new Literal() { Text = "</p>" });
            }

            Table privilegeTable = new Table();
            privilegeTable.Rows.Add(GenerateHeaderRow());
            foreach (var role in editPermissionsData.PermissionSet.RolePrivileges)
            {
                privilegeTable.Rows.Add(GenerateValueRow(role));
            }
            privilegeTable.Rows.Add(GenerateNewRoleRow());
            container.Controls.Add(privilegeTable);

            WikiControlButton saveButton = WikiControlButton.GetFromTemplate(controlSettings.ButtonTemplate);
            saveButton.ButtonControl.Text = "Save Changes";
            saveButton.ButtonControl.Click += saveButtonClick;
            container.Controls.Add(saveButton.RootControl);

            container.Controls.Add(new Literal() { Text = "&nbsp;" });

            WikiControlButton cancelButton = WikiControlButton.GetFromTemplate(controlSettings.ButtonTemplate);
            cancelButton.ButtonControl.Text = "Cancel Changes";
            cancelButton.ButtonControl.Click += cancelButtonClick;
            container.Controls.Add(cancelButton.RootControl);

            controls.Add(container);
        }

        #endregion

        #region Private Methods

        private HtmlGenericControl GeneratePermissionsHierarchy(PermissionsHierarchy hierarchy)
        {
            HtmlGenericControl container = new HtmlGenericControl("div");

            bool firstTime = true;
            foreach (var objectPermissionSet in hierarchy)
            {
                if (firstTime)
                {
                    firstTime = false;
                }
                else
                {
                    container.Controls.Add(new Literal() { Text = "/" });
                }
                Label label = new Label();
                label.Text = objectPermissionSet.Name;
                if (objectPermissionSet.IsActive)
                {
                    label.Style.Add(HtmlTextWriterStyle.TextDecoration, "underline");
                }
                container.Controls.Add(label);
            }

            return container;
        }

        private static TableRow GenerateHeaderRow()
        {
            TableRow header = new TableRow();

            // Command column
            header.Cells.Add(new TableCell());

            // Role name column
            header.Cells.Add(new TableCell() { Text = "Role" });

            // Privilege columns
            foreach (var col in columns)
            {
                header.Cells.Add(new TableCell() { Text = col.HeaderText });
            }

            return header;
        }

        private TableRow GenerateValueRow(RolePrivileges rolePrivileges)
        {
            TableRow row = new TableRow();

            // Command column
            LinkButton deleteLink = new LinkButton();
            deleteLink.Text = "Delete";
            deleteLink.CommandArgument = rolePrivileges.RoleName;
            deleteLink.Click += new EventHandler(deletePermission_Click);
            TableCell cell = new TableCell();
            cell.Controls.Add(deleteLink);
            row.Cells.Add(cell);

            // Role name column
            row.Cells.Add(new TableCell() { Text = rolePrivileges.RoleName });

            // Privilege columns
            foreach (var col in columns)
            {
                CheckBox checkbox = new CheckBox();
                checkbox.ID = col.CheckboxPrefix + rolePrivileges.RoleName;
                checkbox.Checked = col.GetValue(rolePrivileges);
                checkbox.CheckedChanged += new EventHandler(permission_CheckedChanged);
                cell = new TableCell();
                cell.Controls.Add(checkbox);
                row.Cells.Add(cell);
            }

            return row;
        }

        private TableRow GenerateNewRoleRow()
        {
            TableRow row = new TableRow();

            // Command column
            LinkButton addLink = new LinkButton();
            addLink.Text = "Add";
            addLink.Click += new EventHandler(addPermission_Click);
            TableCell cell = new TableCell();
            cell.Controls.Add(addLink);
            row.Cells.Add(cell);

            // Role name column
            TextBox newRole = new TextBox();
            newRole.ID = NEW_ROLE_NAME_TEXTBOX_ID;
            cell = new TableCell();
            cell.Controls.Add(newRole);
            row.Cells.Add(cell);

            // Privilege columns
            foreach (var col in columns)
            {
                CheckBox newCheckbox = new CheckBox();
                newCheckbox.ID = col.NewCheckboxID;
                cell = new TableCell();
                cell.Controls.Add(newCheckbox);
                row.Cells.Add(cell);
            }

            return row;
        }

        #endregion

        #region Local Event Handlers

        private void deletePermission_Click(object sender, EventArgs e)
        {
            editPermissionsData.PermissionSet.RemoveRole(((LinkButton)sender).CommandArgument);
        }

        private void modifyOriginalPermissions_CheckedChanged(object sender, EventArgs e)
        {
            editPermissionsData.ModifyOriginalPermissions = ((CheckBox)sender).Checked;
        }

        private void permission_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkbox = (CheckBox)sender;
            foreach (var col in columns)
            {
                if (checkbox.ID.StartsWith(col.CheckboxPrefix))
                {
                    string role = checkbox.ID.Substring(col.CheckboxPrefix.Length);
                    col.SetValue(editPermissionsData.PermissionSet[role], checkbox.Checked);
                    break;
                }
            }
        }

        private void addPermission_Click(object sender, EventArgs e)
        {
            string role = ((TextBox)WebUtilities.FindControlRecursive(controlsRef[0], NEW_ROLE_NAME_TEXTBOX_ID)).Text;
            RolePrivileges rolePrivileges = editPermissionsData.PermissionSet.AddRole(role);
            foreach (var col in columns)
            {
                col.SetValue(rolePrivileges, ((CheckBox)WebUtilities.FindControlRecursive(controlsRef[0], col.NewCheckboxID)).Checked);
            }
        }

        #endregion
    }
}
